import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { ArrowRight, Swords } from "lucide-react"; import { Container, Eyebrow } from "@/components/marketing/section"; import { Button } from "@/components/ui/button"; import { ProviderIcon } from "@/components/brand/provider-icon"; import { CompareTable } from "@/components/models/compare-table"; import { PROVIDERS } from "@/lib/client/providers"; import { getPublicModels, flagshipModels } from "@/lib/models/public-data"; import { resolveCompareSlug, compareSlug, parseCompareSlug } from "@/lib/models/slug"; import { formatContext, formatPrice } from "@/lib/models/format"; export const dynamic = "force-dynamic"; type Params = Promise<{ slug: string }>; async function resolve(slug: string) { if (!parseCompareSlug(slug)) return null; const { models, ctx } = await getPublicModels(); const chosen = resolveCompareSlug(models, slug); return chosen ? { chosen, models, ctx } : null; } function names(models: { displayName: string }[]): string { return models.map((m) => m.displayName).join(" vs "); } export async function generateMetadata({ params }: { params: Params }): Promise { const { slug } = await params; const r = await resolve(slug); if (!r) return { title: "Comparison not found", robots: { index: false } }; const title = `${names(r.chosen)} — pricing, context & capabilities`; const description = r.chosen.map((m) => `${m.displayName} (${PROVIDERS[m.provider].shortName}): ${formatPrice(m.pricing?.inputPerMillion)} in / ${formatPrice(m.pricing?.outputPerMillion)} out per 1M tokens, ${formatContext(m.limits?.contextTokens)} context`).join(" · ") + ". Compared side by side on PolyLLM."; const canonical = `/compare/${compareSlug(r.chosen)}`; return { title, description, alternates: { canonical }, openGraph: { title: `${names(r.chosen)} — PolyLLM`, description, url: canonical } }; } export default async function ComparePage({ params }: { params: Params }) { const { slug } = await params; const r = await resolve(slug); if (!r) notFound(); const { chosen, models, ctx } = r; const arenaHref = `/app/arena?models=${encodeURIComponent(chosen.map((m) => m.key).join(","))}`; const chosenKeys = new Set(chosen.map((m) => m.key)); const related = flagshipModels(models, 6) .filter((f) => !chosenKeys.has(f.key)) .slice(0, 4) .map((f) => ({ f, slug: compareSlug([chosen[0], f]) })); return ( <>
Model comparison

{chosen.map((m, i) => ( {i > 0 ? vs : null} {m.displayName} ))}

{chosen.map((m) => `${PROVIDERS[m.provider].name}’s ${m.displayName}`).join(" and ")} compared on price per million tokens, context window, output limits, reasoning controls and every capability PolyLLM tracks — from the providers’ own listings, nothing guessed.

{related.length ? (

More comparisons with {chosen[0].displayName}

    {related.map(({ f, slug: s }) => (
  • {chosen[0].displayName} vs {f.displayName}
  • ))}
) : null}

Run the same prompt on {chosen.length === 2 ? "both" : "all of them"}.

PolyLLM Arena streams the answers side by side with latency, tokens and cost — with your own API keys, encrypted.

Prices are the providers’ published list prices in USD per million tokens at the last catalog audit. Release dates and knowledge cutoffs appear only when the provider publishes them.

); }